package cn.edu.sdjzu.xg.eagle.factory;

import cn.edu.sdjzu.xg.eagle.exception.BaseException;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

/**
 * 服务工厂类，用于动态加载和实例化服务接口的实现类。支持单例模式。
 */
public class ServiceFactory {
    private static final String servicePackageName = "cn.edu.sdjzu.xg.eagle.service.impl";
    // 使用一个HashMap来存储接口类到其实例的映射，实现单例模式
    private static final Map<Class<?>, Object> serviceInstances = new HashMap<>();

    /**
     * 根据服务接口和服务名称动态获取服务实现类的实例，实现单例。
     *
     * @param serviceInterface 服务接口的Class对象
     * @param serviceName      服务实现类的简单名称（不包含包名）
     * @param <T>              服务接口的类型
     * @return 返回实现了指定服务接口的服务实现类的实例，为单例
     * @throws BaseException 如果在动态加载或实例化过程中发生错误。
     * 如果BaseException为必检查异常，会导致getService方法的用户被迫定义Service实现类的构造器并声明这个异常
     */
    public static <T> T getService(Class<T> serviceInterface, String serviceName)
            throws BaseException {
        // 首先检查实例是否已经存在于映射中
        synchronized (serviceInstances) {
            @SuppressWarnings("unchecked")
            T instance = (T) serviceInstances.get(serviceInterface);
            if (instance != null) {
                // 如果实例已存在，直接返回这个实例
                return instance;
            }

            try {
                // 动态加载指定服务名称的类
                Class<?> clazz = Class.forName(servicePackageName + "." + serviceName);
                // 检查加载的类是否实现了指定的服务接口
                if (!serviceInterface.isAssignableFrom(clazz)) {
                    throw new BaseException("类 " + serviceName + " 没有实现接口 " + serviceInterface.getName());
                }
                // 使用反射创建服务实现类的实例
                instance = (T) clazz.getDeclaredConstructor().newInstance();
                // 将新创建的实例存储到映射中，实现单例
                serviceInstances.put(serviceInterface, instance);
                return instance;
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
                throw new BaseException("在包 " + servicePackageName + " 中找不到服务类 " + serviceName, e);
            } catch (InstantiationException | IllegalAccessException | NoSuchMethodException e) {
                e.printStackTrace();
                throw new BaseException("在实例化服务类 " + serviceName + " 时发生错误", e);
            } catch (InvocationTargetException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }
    }
}